﻿using System;
using System.Collections.Generic;
using System.Data.Objects.DataClasses;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using System.Data.Objects;
using System.Collections;
using HanGu.Entity;
using HanGu.Entity.Enum;

namespace HanGu.Services
{
    public class BaseService
    {

        #region 数据操作方法
        //创建数据库连接
        //public HaiGuEntities dbConn;

        /// <summary>
        ///  在构造函数中初始化数据库连接
        /// </summary>
        public BaseService()
        {
            //dbConn = new HaiGuEntities();
        }

        /// <summary>
        /// 新增实体信息
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="entity"></param>
        /// <returns></returns>
        protected TEntity Add<TEntity>(TEntity entity)
        {
            using (HaiGuEntities dbConn = new HaiGuEntities())
            {
                try
                {
                    dbConn.AddObject(entity.GetType().Name, entity);
                    dbConn.SaveChanges();
                    return entity;
                }
                catch (Exception e)
                {
                    ExceptionHand(e);

                    return entity;
                }
            }

        }

        /// <summary>
        /// 修改实体信息
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="entity"></param>
        /// <returns></returns>
        protected TEntity Update<TEntity>(TEntity entity) where TEntity : class
        {
            using (HaiGuEntities dbConn = new HaiGuEntities())
            {
                try
                {
                    var key = dbConn.CreateEntityKey(entity.GetType().Name, entity);
                    object obj;
                    if (dbConn.TryGetObjectByKey(key, out obj))
                    {
                        dbConn.ApplyCurrentValues<TEntity>(entity.GetType().Name, entity);
                    }
                    else
                    {
                        dbConn.AttachTo(entity.GetType().Name, entity);
                    }
                    dbConn.SaveChanges();
                    return entity;
                }
                catch (Exception e)
                {
                    ExceptionHand(e);

                    return entity;
                }
            }


        }



        /// <summary>
        /// 根据条件，删除一个实体
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="condition"></param>
        /// <returns></returns>
        public TEntity Delete<TEntity>(Expression<Func<TEntity, bool>> where) where TEntity : EntityObject
        {
            using (HaiGuEntities dbConn = new HaiGuEntities())
            {
                TEntity entity = null;
                try
                {
                    entity = dbConn.CreateObjectSet<TEntity>().Where(where).FirstOrDefault();
                    if (entity == null) return null;
                    dbConn.DeleteObject(entity);
                    dbConn.SaveChanges();
                    return entity;
                }
                catch (Exception e)
                {
                    ExceptionHand(e);

                    return entity;
                }

            }

        }

        /// <summary>
        /// 根据条件查询，返回一个实体
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="condition"></param>
        /// <returns></returns>
        public TEntity GetBy<TEntity>(Expression<Func<TEntity, bool>> condition) where TEntity : EntityObject
        {
            using (HaiGuEntities dbConn = new HaiGuEntities())
            {
                TEntity entity = null;
                try
                {
                    entity = dbConn.CreateObjectSet<TEntity>().Where(condition).FirstOrDefault();
                    return entity;
                }
                catch (Exception e)
                {
                    ExceptionHand(e);

                    return entity;
                }

            }

        }

        /// <summary>
        /// 根据固定条件查询，返回一个实体集合
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="condition"></param>
        /// <returns></returns>
        public List<TEntity> GetList<TEntity, TOrderBy>(Expression<Func<TEntity, bool>> condition, Expression<Func<TEntity, TOrderBy>> orderby)
            where TEntity : EntityObject
            where TOrderBy : class
        {
            using (HaiGuEntities dbConn = new HaiGuEntities())
            {
                try
                {
                    return dbConn.CreateObjectSet<TEntity>().Where(condition).OrderBy(condition).ToList<TEntity>();
                }
                catch (Exception e)
                {
                    ExceptionHand(e);

                    return null;
                }
            }

        }

        public IQueryable<TEntity> Paging<TEntity>(IQueryable<TEntity> iQueryable, PaginationDTO paginatonDTO)
            where TEntity : EntityObject
        {
            if (paginatonDTO.ReCount)
            {
                paginatonDTO.RowCount = iQueryable.Count();
            }
            if (paginatonDTO.IsPaging)
            {
                iQueryable = iQueryable.OrderBy(c => 1 == 1).Skip(paginatonDTO.PageSize * (paginatonDTO.CurrentIndex - 1)).Take(paginatonDTO.PageSize);

            }
            return iQueryable;

        }

        public IQueryable<TEntity> Paging<TEntity, TOrderByDesc>(Expression<Func<TEntity, TOrderByDesc>> orderbyDescending, IQueryable<TEntity> iQueryable, PaginationDTO paginatonDTO)
             where TEntity : EntityObject
        //where TOrderByDesc : object
        {
            if (paginatonDTO.ReCount)
            {
                paginatonDTO.RowCount = iQueryable.Count();
            }
            if (paginatonDTO.IsPaging)
            {
                iQueryable = iQueryable.OrderByDescending(orderbyDescending).Skip(paginatonDTO.PageSize * (paginatonDTO.CurrentIndex - 1)).Take(paginatonDTO.PageSize);
            }
            else
            {
                iQueryable = iQueryable.OrderByDescending(orderbyDescending);
            }
            return iQueryable;

        }
        public IQueryable<TEntity> Paging<TEntity, TOrderByDesc>(Expression<Func<TEntity, Int32?>> orderbyAsc, Expression<Func<TEntity, TOrderByDesc>> orderbyDescending, IQueryable<TEntity> iQueryable, PaginationDTO paginatonDTO)
              where TEntity : EntityObject
        //where TOrderByDesc : object
        {
            if (paginatonDTO.ReCount)
            {
                paginatonDTO.RowCount = iQueryable.Count();
            }

            iQueryable = iQueryable.OrderBy(orderbyAsc).ThenByDescending(orderbyDescending);

            if (paginatonDTO.IsPaging)
            {
                iQueryable = iQueryable.Skip(paginatonDTO.PageSize * (paginatonDTO.CurrentIndex - 1)).Take(paginatonDTO.PageSize);
            }
            else
            {
                iQueryable = iQueryable.OrderByDescending(orderbyDescending);
            }
            return iQueryable;

        }

        #endregion

        #region 日志记录

        protected void ExceptionHand(Exception e)
        {
            string title = this.ToString() + e.TargetSite;
            string message = e.Source + "_" + e.Message + Environment.NewLine + e.StackTrace;
            WriteGeneralLog(title, message, Priority.Normal);
            throw e;
        }

        /// <summary>
        /// 异常错误日志记录
        /// </summary>
        /// <param name="p_Title">标题</param>
        /// <param name="p_Message">内容</param>
        /// <param name="p_Priority">级别</param>
        /// <returns></returns>
        public void WriteGeneralLog(string p_Title, string p_Message, Priority p_Priority)
        {
            try
            {
                this.WriteLog(p_Title, p_Message, p_Priority, Category.General);
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        /// <summary>
        /// 跟踪日志记录
        /// </summary>
        /// <param name="p_Title">标题</param>
        /// <param name="p_Message">内容</param>
        /// <param name="p_Priority">级别</param>
        /// <returns></returns>
        public void WriteTraceLog(string p_Title, string p_Message, Priority p_Priority)
        {
            try
            {
                this.WriteLog(p_Title, p_Message, p_Priority, Category.Trace);
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        private void WriteLog(string p_Title, string p_Message, Priority p_Priority, string p_Category)
        {
            try
            {
                int priority = (int)p_Priority;
                string category = p_Category.ToString();

                LogEntry logEntry = new LogEntry();

                logEntry.TimeStamp = DateTime.Now;
                logEntry.Title = p_Title;
                logEntry.Message = p_Message;
                logEntry.Priority = priority;
                logEntry.Categories.Add(category);

                Logger.Write(logEntry, category);
            }
            catch (Exception e)
            {
                throw e;
            }
        }
        #endregion

        /// <summary>
        /// 根据条件数据动态生成或连接条件
        /// </summary>
        /// <typeparam name="TSource">集合项类型</typeparam>
        /// <param name="sourcePropertyName">待比较的集合项属性</param>
        /// <param name="methodName">方法名称</param>
        /// <param name="objs">条件数据</param>
        /// <returns></returns>
        public Expression<Func<TSource, bool>> GenerateOrElseConditionWithArray<TSource>(string sourcePropertyName, string methodName, IEnumerable<object> objs)
        {
            if (objs != null && objs.Count() > 0)
            {
                var len = objs.Count();
                var p = Expression.Parameter(typeof(TSource), "p");
                var propertyName = Expression.Property(p, sourcePropertyName);
                var body = Expression.GreaterThanOrEqual(Expression.Call(propertyName, methodName, null, Expression.Constant(objs.First())), Expression.Constant(0, typeof(int)));
                for (int i = 1; i < len; i++)
                {
                    var pcode = objs.ElementAt(i);
                    body = Expression.OrElse(body, Expression.GreaterThanOrEqual(Expression.Call(propertyName, methodName, null, Expression.Constant(pcode)), Expression.Constant(0, typeof(int))));//Expression.Call(propertyName, methodName, null, Expression.Constant(pcode)));
                }
                Expression<Func<TSource, bool>> orExp = Expression.Lambda<Func<TSource, bool>>(body, p);
                return orExp;
            }
            return null;
        }

        #region commont
        //http://msdn.microsoft.com/en-us/library/bb882637.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1
        //http://www.cnblogs.com/newton/archive/2012/12/17/2821159.html
        //// Add a using directive for System.Linq.Expressions. 

        //    string[] companies = { "Consolidated Messenger", "Alpine Ski House", "Southridge Video", "City Power & Light",
        //                       "Coho Winery", "Wide World Importers", "Graphic Design Institute", "Adventure Works",
        //                       "Humongous Insurance", "Woodgrove Bank", "Margie's Travel", "Northwind Traders",
        //                       "Blue Yonder Airlines", "Trey Research", "The Phone Company",
        //                       "Wingtip Toys", "Lucerne Publishing", "Fourth Coffee" };

        //    // The IQueryable data to query.
        //    IQueryable<String> queryableData = companies.AsQueryable<string>();

        //    // Compose the expression tree that represents the parameter to the predicate.
        //    ParameterExpression pe = Expression.Parameter(typeof(string), "company");

        //    // ***** Where(company => (company.ToLower() == "coho winery" || company.Length > 16)) *****
        //    // Create an expression tree that represents the expression 'company.ToLower() == "coho winery"'.
        //    Expression left = Expression.Call(pe, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));
        //    Expression right = Expression.Constant("coho winery");
        //    Expression e1 = Expression.Equal(left, right);

        //    // Create an expression tree that represents the expression 'company.Length > 16'.
        //    left = Expression.Property(pe, typeof(string).GetProperty("Length"));
        //    right = Expression.Constant(16, typeof(int));
        //    Expression e2 = Expression.GreaterThan(left, right);

        //    // Combine the expression trees to create an expression tree that represents the 
        //    // expression '(company.ToLower() == "coho winery" || company.Length > 16)'.
        //    Expression predicateBody = Expression.OrElse(e1, e2);

        //    // Create an expression tree that represents the expression 
        //    // 'queryableData.Where(company => (company.ToLower() == "coho winery" || company.Length > 16))'
        //    MethodCallExpression whereCallExpression = Expression.Call(
        //        typeof(Queryable),
        //        "Where",
        //        new Type[] { queryableData.ElementType },
        //        queryableData.Expression,
        //        Expression.Lambda<Func<string, bool>>(predicateBody, new ParameterExpression[] { pe }));
        //    // ***** End Where ***** 

        //    // ***** OrderBy(company => company) ***** 
        //    // Create an expression tree that represents the expression 
        //    // 'whereCallExpression.OrderBy(company => company)'
        //    MethodCallExpression orderByCallExpression = Expression.Call(
        //        typeof(Queryable),
        //        "OrderBy",
        //        new Type[] { queryableData.ElementType, queryableData.ElementType },
        //        whereCallExpression,
        //        Expression.Lambda<Func<string, string>>(pe, new ParameterExpression[] { pe }));
        //    // ***** End OrderBy ***** 

        //    // Create an executable query from the expression tree.
        //    IQueryable<string> results = queryableData.Provider.CreateQuery<string>(orderByCallExpression);

        //    // Enumerate the results. 
        //    foreach (string company in results)
        //        Console.WriteLine(company);

        //    /*  This code produces the following output:

        //        Blue Yonder Airlines
        //        City Power & Light
        //        Coho Winery
        //        Consolidated Messenger
        //        Graphic Design Institute
        //        Humongous Insurance
        //        Lucerne Publishing
        //        Northwind Traders
        //        The Phone Company
        //        Wide World Importers
        //    */
        #endregion
    }
}
